package cn.xinfei.xdecision.engine.runner.expressions;

import cn.xinfei.xdecision.common.service.script.groovy.ScriptTemplate;
import cn.xinfei.xdecision.common.utils.util.runner.StrUtils;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.EvaluationException;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.Evaluator;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.function.math.Groovy;
import cn.xinfei.xdecision.common.utils.util.runner.jeval.function.math.Python;
import cn.xinfei.xdecision.common.vo.FieldInfoVo;
import cn.xinfei.xdecision.engine.runner.context.AmmunitionDepot;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class ScriptExecutor {


    private static final String replaceGroovyScript(String formula, Map<String, Object> data, Map<String, FieldInfoVo> fieldInfo) {
        //替换掉特殊的字符
        formula = formula.replace("&gt;", ">"); //3&gt;=6 && 3&lt; 12
        formula = formula.replace("&lt;", "<");
        //正则匹配自定义中用到的变量对其进行替换
        Pattern pattern = Pattern.compile("@[a-zA-Z0-9_\u4e00-\u9fa5()（）-]+@");
        Matcher matcher = pattern.matcher(formula);
        String subexp = formula;
        String exp = "";
        int j = 0;
        while (matcher.find()) {
            String fieldCN = matcher.group(0).replace("@", "");
            FieldInfoVo subField = fieldInfo.get(fieldCN);
            if (subField == null) {
                return "";
            }
            String fieldEn = subField.getFieldCode();
            String v = "";
//            Object valueByKey = PipelineContextHolder.getValueByKey(fieldEn);
            Object valueByKey =  AmmunitionDepot.getValueByKeyFromRemote(fieldEn);
            if (null == valueByKey) {
                valueByKey = subField.getVarDefaultValue();
            }
            v = "" + valueByKey;
            data.put(fieldEn, valueByKey);
            if (subexp.contains("def main")) {
                // groovy脚本替换为动态参数
                v = "_['" + fieldEn + "']";
                exp += subexp.substring(j, matcher.end()).replace("@" + fieldCN + "@", v);
            } else {
                if (subField.getValueType() == 1 || subField.getValueType() == 4) {
                    exp += subexp.substring(j, matcher.end()).replace("@" + fieldCN + "@", v);
                } else {
                    exp += subexp.substring(j, matcher.end()).replace("@" + fieldCN + "@", "'" + v + "'");
                }
            }
            j = matcher.end();
        }
        exp += formula.substring(j, formula.length());
        return exp;
    }

    private static final String replaceGroovyScript(String formula, Map<String, FieldInfoVo> fieldInfo) {
        //替换掉特殊的字符
        //正则匹配自定义中用到的变量对其进行替换
        Pattern pattern = Pattern.compile("\\$[a-zA-Z0-9_\u4e00-\u9fa5()（）-]+\\$");
        Matcher matcher = pattern.matcher(formula);
        String subexp = formula;
        String exp = "";
        int j = 0;
        while (matcher.find()) {
            String fieldCN = matcher.group(0).replace("$", "");
            FieldInfoVo subField = fieldInfo.get(fieldCN);
            if (subField == null) {
                return "";
            }
            String fieldEn = subField.getFieldCode();
            if (subexp.contains("def main")) {
                // groovy脚本替换为动态参数
                exp += subexp.substring(j, matcher.end()).replace("$" + fieldCN + "$", "\"" + fieldEn + "\"");
            } else {
                exp += subexp.substring(j, matcher.end()).replace("$" + fieldCN + "$", "\"" + fieldEn + "\"");
            }
            j = matcher.end();
        }
        exp += formula.substring(j, formula.length());
        return exp;
    }

    //执行自定义脚本
    public static final Object executeScript(JSONObject formulaJson, Map<String, FieldInfoVo> fieldInfo) throws EvaluationException {

        String formula = formulaJson.getString("formula");
        formula = formula.replace("&gt;", ">"); //3&gt;=6 && 3&lt; 12
        formula = formula.replace("&lt;", "<");
        Map<String, Object> data = new HashMap<>();
        //替换@符号
        formula = ScriptTemplate.replaceGroovyScript(formula);
        String exp = replaceGroovyScript(formula, data, fieldInfo);
        exp = replaceGroovyScript(exp, fieldInfo);

        Evaluator evaluator = new Evaluator();
        Object result = "";
        try {
            if (exp.contains("def main")) {
                // 执行groovy脚本
//                log.debug("groovy:{},{}", exp, data);
                result = Groovy.getInstance().executeForObject(exp, data);
            } else if (exp.contains("def python_main(_):")) {
                //执行python脚本
                result = Python.getInstance().executeForObject(exp, data);
            } else {
                //执行公式
                result = evaluator.evaluate(exp);
            }
            if (result.toString().startsWith("'")) {
                //字符串
                result = result.toString().replace("'", "");
            } else {
                //数值
                if (StrUtils.isNum(result.toString())) {
                    String[] split = result.toString().split("\\.");
                    if (split.length > 1 && StrUtils.strToLong(split[1]) > 0) {
                        result = StrUtils.strToDouble(result.toString());
                    } else {
                        result = StrUtils.strToLong(split[0]);
                    }
                }
            }
        } catch (EvaluationException e) {
            log.error("自定义执行异常,exp={},data={}", exp, JSON.toJSONString(data), e);
//            throw new ApiException(ErrorCodeEnum.RUNNER_CUSTOM_ERROR.getCode(), ErrorCodeEnum.RUNNER_CUSTOM_ERROR.getMessage());
            throw e;
        }
        return result;
    }

    //对groovy脚本执行结果进一步处理
    public static Map handleGroovyResult(Map map) {

        Iterator<Map.Entry<String, Object>> iterator = map.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            if (entry.getKey().startsWith("_['") && entry.getKey().endsWith("']")) {
                map.remove(entry.getKey());
                String key = entry.getKey().replace("_['", "").replace("']", "");
                map.put(key, entry.getValue());
            }
        }
        return map;
    }


}
